package com.yycx.module.pay.provider.service.impl;

import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipaySystemOauthTokenRequest;
import com.alipay.api.response.AlipaySystemOauthTokenResponse;
import com.yycx.common.base.entity.EntityMap;
import com.yycx.common.base.service.BaseAppAccountService;
import com.yycx.common.base.utils.FlymeUtils;
import com.yycx.common.enums.AccountTypeEnum;
import com.yycx.common.mybatis.base.service.impl.BaseServiceImpl;
import com.yycx.common.mybatis.model.ResultBody;
import com.yycx.common.mybatis.query.CriteriaQuery;
import com.yycx.common.security.OpenHelper;
import com.yycx.common.utils.ApiAssert;
import com.yycx.module.pay.client.entity.PayBalance;
import com.yycx.module.pay.client.entity.PayBalanceLog;
import com.yycx.module.pay.client.entity.PayConfig;
import com.yycx.module.pay.client.vo.PayRequest;
import com.yycx.module.pay.provider.mapper.PayBalanceMapper;
import com.yycx.module.pay.provider.service.PayBalanceLogService;
import com.yycx.module.pay.provider.service.PayBalanceService;
import com.yycx.module.pay.provider.service.PayConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;

/**
 * 余额表 实现类
 *
 * @author flyme
 * @date 2019-12-16
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class PayBalanceServiceImpl extends BaseServiceImpl<PayBalanceMapper, PayBalance> implements PayBalanceService {

    @Resource
    private PayBalanceLogService payBalanceLogService;

    @Autowired(required = false)
    private BaseAppAccountService baseAppAccountService;

    @Autowired(required = false)
    private PayConfigService payConfigService;

    @Override
    public ResultBody beforePageList(CriteriaQuery<PayBalance> cq, PayBalance balance, EntityMap requestMap) {
        cq.select("user.userName", "user.nickName", "user.mobile");
        cq.select(PayBalance.class, "*");
        cq.eq("user.userName", requestMap.get("userName"));
        cq.eq("user.mobile", requestMap.get("mobile"));
        cq.createJoinAppUser();
        return super.basePageList(cq);
    }

    @Override
    public PayBalance getByUserIdAndUserType(Long userId, String userType) {
        return getByUserIdAndUserType(userId, userType, true);
    }

    @Override
    public boolean addBalance(Long userId, String userType, BigDecimal amount, String outTradeNo, Integer type, Long busId, String title, String body) {
        PayBalance balance = getByUserIdAndUserType(userId, userType);
        balance.setAmount(balance.getAmount().add(amount));
        boolean update = balance.updateById();
        //余额变动有乐观锁，高并发的时候会更新失败。
        if (update) {
            PayBalanceLog balanceLog = new PayBalanceLog();
            balanceLog.setUserId(userId).setUserType(userType).setBalanceId(balance.getBalanceId()).setAmount(amount).setTradeNo(outTradeNo).setLogType(type).setBusId(busId).setTitle(title).setBody(body);
            payBalanceLogService.save(balanceLog);
        }
        return update;
    }

    @Override
    public boolean subtractBalance(PayRequest payRequest) {
        Long userId = payRequest.getUserId();
        String userType = payRequest.getUserType();
        PayBalance balance = getByUserIdAndUserType(userId, userType, false);
        ApiAssert.isNotEmpty("账户余额不足!", balance);
        Object appScanPay = payRequest.getAppScanPay();
        if (FlymeUtils.isEmpty(appScanPay)) {
            Boolean isCheckPayPwd = payRequest.getIsCheckPayPwd();
            if (isCheckPayPwd) {
                String dbPayPwd = balance.getPaypwd();
                ApiAssert.isNotEmpty("请设置支付密码", dbPayPwd);
                //支付密码
                String payPwd = payRequest.getPayPwd();
                ApiAssert.eq("支付密码不正确", payPwd, dbPayPwd);
            }
        }
        Boolean useBindAmount = payRequest.getUseBindAmount();
        //账户余额
        BigDecimal balanceAmount = FlymeUtils.getBigDecimal(balance.getAmount(), "0");
        //支付金额
        BigDecimal payAmount = payRequest.getPayAmount();
        if (FlymeUtils.isNotEmpty(useBindAmount) && useBindAmount) {
            //绑定金使用模式1.混用,2仅使用绑定金
            Integer useBindAmountType = payRequest.getUseBindAmountType();
            //绑定金余额
            BigDecimal bindAmount = FlymeUtils.getBigDecimal(balance.getBindAmount(), "0");
            if (useBindAmountType.equals(1)) {
                //账户总金额
                BigDecimal totalAmount = balanceAmount.add(bindAmount);
                if (FlymeUtils.lt(totalAmount, payAmount)) {
                    ApiAssert.failure("账户余额不足!");
                }
                if (FlymeUtils.gezero(bindAmount)) {
                    //绑定金够支付的情况
                    if (FlymeUtils.ge(bindAmount, payAmount)) {
                        balance.setBindAmount(bindAmount.subtract(payAmount));
                    }
                    //绑定金不够支付的情况
                    if (FlymeUtils.lt(bindAmount, payAmount)) {
                        BigDecimal surplusAmount = payAmount.subtract(bindAmount);
                        balance.setBindAmount(new BigDecimal("0"));
                        balance.setAmount(balanceAmount.subtract(surplusAmount));
                    }
                }
            }
            if (useBindAmountType.equals(2)) {
                if (FlymeUtils.lt(bindAmount, payAmount)) {
                    ApiAssert.failure("账户余额不足!");
                }
                balance.setBindAmount(bindAmount.subtract(payAmount));
            }
        } else {
            balance.setAmount(balanceAmount.subtract(payAmount));
            if (FlymeUtils.lt(balanceAmount, payAmount)) {
                ApiAssert.failure("余额不足");
            }
            balance.setAmount(balanceAmount.subtract(payAmount));
        }
        boolean update = balance.updateById();
        //余额变动有乐观锁，高并发的时候会更新失败。
        PayBalanceLog balanceLog = new PayBalanceLog();
        balanceLog.setUserId(userId).
                setUserType(userType).
                setBalanceId(balance.getBalanceId()).
                setAmount(new BigDecimal("-" + payAmount)).
                setTradeNo(payRequest.getOutTradeNo()).
                setLogType(payRequest.getLogType()).
                setBusId(payRequest.getBusId()).
                setTitle("买入商品").
                setBody(payRequest.getBody()).
                setStatus(2);
        balanceLog.insert();
        if (update) {
            balanceLog.setStatus(3);
        }
        return update;
    }


    @Override
    public PayBalance addUserBalance(Long userId) {
        PayBalance balance = getByUserId(userId);
        if (FlymeUtils.isEmpty(balance)) {
            balance = new PayBalance();
            balance.setUserId(userId);
            balance.setBalanceId(userId);
            balance.setVersion(100L);
            balance.setCompanyId(OpenHelper.getCompanyId());
            balance.setAmount(new BigDecimal("0"));
            balance.setBindAmount(new BigDecimal("0"));
            save(balance);
        }
        return balance;
    }

    @Override
    public ResultBody setPayPwd(String payPwd, String smsCode) {
        Long userId = OpenHelper.getUserId();
        if (FlymeUtils.isNotEmpty(baseAppAccountService)) {
            EntityMap entityMap = baseAppAccountService.getAppAccount(userId, AccountTypeEnum.MOBILE.getCode());
            String account = entityMap.get("account");
            //校验验证码
            commonBeanUtils.validSmsCode(account, smsCode);
        }
        // String encodePassword = passwordEncoder.encode(paypwd);
        PayBalance balance = addUserBalance(userId);
        balance.setPaypwd(payPwd);
        updateById(balance);
        return ResultBody.msg("设置成功");
    }


    @Override
    public PayBalance getByUserId(Long userId) {
        return getByProperty("userId", userId);
    }

    @Override
    public Boolean addBindAmount(Long userId, Long sourceUserId, BigDecimal amount) {
        return addBindAmount(userId, sourceUserId, amount, 1, "邀请奖励", "收益");
    }

    @Override
    public Boolean addBindAmount(Long userId, Long sourceUserId, BigDecimal amount, Integer logType, String title, String body) {
        PayBalance balance = getByUserId(userId);
        if (FlymeUtils.isEmpty(balance)) {
            //当推荐人账户不存在时创建账户
            balance = new PayBalance();
            balance.setUserId(userId);
            balance.setBindAmount(amount);
            balance.setVersion(100L);
            balance.setAmount(new BigDecimal("0"));
            save(balance);
        } else {
            BigDecimal bindAmount = balance.getBindAmount();
            balance.setBindAmount(bindAmount.add(amount));
            updateById(balance);
        }
        return payBalanceLogService.addBalanceLog(balance.getBalanceId(), userId, amount, body, title, logType, sourceUserId,null);
    }

    @Override
    public ResultBody bindCashAccount(Integer bindCashType, String cashAccount) {
        ApiAssert.allNotNull("缺少必要参数", bindCashType, cashAccount);
        Long userId = OpenHelper.getUserId();
        PayBalance payBalance = addUserBalance(userId);
        if (bindCashType == 1) {
            payBalance.setWxOpenId(cashAccount);
        }
        if (bindCashType == 2) {
            payBalance.setAliPayAccount(cashAccount);
        }
        if (bindCashType == 3) {
            payBalance.setWxAppOpenId(cashAccount);
        }
        updateById(payBalance);
        return ResultBody.ok("绑定成功");
    }

    @Override
    public ResultBody getAliUserInfoByAuthCode(String authCode, Long payId) {
        if (FlymeUtils.isEmpty(authCode)) {
            return ResultBody.failed("auth_code不能为空");
        }
        if (FlymeUtils.isEmpty(payId)) {
            return ResultBody.failed("payId不能为空");
        }
        PayConfig payConfig = payConfigService.getById(payId);
        String appId = payConfig.getAppId();
        String privateKey = payConfig.getPrivateKey();
        String publicKey = payConfig.getPublicKey();
        String inputCharset = payConfig.getInputCharset();
        String signType = payConfig.getSignType();
        AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do", appId, privateKey, "json", inputCharset, publicKey, signType);
        AlipaySystemOauthTokenRequest request = new AlipaySystemOauthTokenRequest();
        request.setCode(authCode);
        request.setGrantType("authorization_code");
        try {
            AlipaySystemOauthTokenResponse oauthTokenResponse = alipayClient.execute(request);
            return ResultBody.ok(oauthTokenResponse);
        } catch (AlipayApiException e) {
            //处理异常
            e.printStackTrace();
        }
        return ResultBody.failed("获取失败");
    }

    /**
     * 创建用户账户
     *
     * @param userId
     * @param userType
     * @param isReturn 是否返回账户对象
     * @return
     */
    private PayBalance getByUserIdAndUserType(Long userId, String userType, Boolean isReturn) {
        CriteriaQuery<PayBalance> cq = new CriteriaQuery(PayBalance.class);
        PayBalance balance = getOne(cq.eq("userId", userId).eq("userType", userType));
        //如果用户的余额为空，重新插入余额。
        if (FlymeUtils.isEmpty(balance)) {
            PayBalance addPayBalance = new PayBalance();
            addPayBalance.setUserId(userId).setUserType(userType).setCommAmount(new BigDecimal(0)).setBindAmount(new BigDecimal(0)).setAmount(new BigDecimal(0)).setVersion(new Long(1));
            addPayBalance.insert();
            if (isReturn) {
                balance = addPayBalance;
            }
        }
        return balance;
    }
}
